package org.totoro.nio;

import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
 * 内存映射
 * <p>
 * 参考：https://blog.csdn.net/ybur11/article/details/103210144
 *
 * @author daocr
 * @date 2020/5/6
 */
public class MappedByteBufferTest {

    private final int _1MB = 1 * 1024 * 1024;

    public final String path = "./";
    private final String fileName = "mappedByteBuffer.json";

    /**
     * MapMode mode：内存映像文件访问的方式，共三种：
     *
     * @throws IOException
     * @see java.nio.channels.FileChannel.MapMode#READ_ONLY ：只读，试图修改得到的缓冲区将导致抛出异常。
     * @see java.nio.channels.FileChannel.MapMode#READ_WRITE：读/写，对得到的缓冲区的更改最终将写入文件；但该更改对映射到同一文件的其他程序不一定是可见的。
     * @see java.nio.channels.FileChannel.MapMode#PRIVATE：私用，可读可写,但是修改的内容不会写入文件，只是buffer自身的改变，这种能力称之为”copy on write”。
     */
    @Test
    public void createMappedBuffer() throws IOException {

        File file = new File(path + fileName);
        // 创建映射 文件

        MappedByteBuffer map = new RandomAccessFile(file, "rw")
                .getChannel()
                .map(FileChannel.MapMode.READ_ONLY, 0, _1MB);
    }

    /**
     * 读取内存映射文件
     */
    @Test
    public void openMappedBuffer() throws IOException {

        getMappedByteBuffer();
    }


    /**
     * 读取和写入内存 内存映射文件
     *
     * @throws IOException
     * @see MappedByteBuffer#capacity() 文件总大小
     * @see MappedByteBuffer#arrayOffset()  获取偏移量
     * @see MappedByteBuffer#get()
     */
    @Test
    public void readAndWrite() throws IOException {

        MappedByteBuffer mappedByteBuffer = getMappedByteBuffer();

        // 总大小
        int capacity = mappedByteBuffer.capacity();
        byte b = mappedByteBuffer.get();
        System.out.println(b);

        System.out.println("文件总大小：" + capacity + " byte"
                + "偏移量：" );

    }


    private MappedByteBuffer getMappedByteBuffer() throws IOException {

        Path path = FileSystems.getDefault().getPath(this.path, fileName);

        // 2、创建内存映射文件
        FileChannel fileChannel =   new RandomAccessFile(path.toFile(),"rw" ).getChannel();

        MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size());
        return mappedByteBuffer;

    }

}
